home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Heretic Source / D_NETBAK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-10  |  15.5 KB  |  798 lines

  1.  
  2. // I_pcnet.m
  3. //
  4. // Modified 12-21-94 by Chris Rhinehart for use with multiple ticdups
  5. //        actually, it wasn't modified, but rather we are currently using this
  6. //     older version of D_NET.C, since the new one doesn't seem to work with
  7. //        ticdup set to greater than one.
  8.  
  9. #include "DoomDef.h"
  10. #include "P_local.h"
  11. #include "soundst.h"
  12.  
  13. #define    NCMD_EXIT        0x80000000
  14. #define    NCMD_RETRANSMIT    0x40000000
  15. #define    NCMD_SETUP        0x20000000
  16. #define    NCMD_CHECKSUM    0x0fffffff
  17.  
  18. /*
  19. if more space needs to be crunched out of the protocol...
  20.  
  21. 1    drone
  22. 2    player
  23. 8    tic
  24. 5    numtics
  25.  
  26. #define    NCMD_EXIT        0x80000000
  27. #define    NCMD_RETRANSMIT    0x40000000            // a retransmit will have 0 tics
  28. #define    NCMD_DRONE        0x20000000
  29. #define    NCMD_PLAYER        0x18000000
  30. #define    NCMD_PLAYERSHIFT    27
  31. #define    NCMD_TIC        0x00ff0000
  32. #define    NCMD_TICSHIFT    16
  33. #define    NCMD_NUMTICS    0x0000ff00
  34. #define    NCMD_NUMTICSSHIFT    8
  35. #define    NCMD_CHECKSUM    0x000000ff
  36.  
  37. */
  38.  
  39.  
  40.  
  41.  
  42.  
  43. doomcom_t        *doomcom;
  44. doomdata_t        *netbuffer;        // points inside doomcom
  45.  
  46.  
  47. /*
  48. ==============================================================================
  49.  
  50.                             NETWORKING
  51.  
  52. gametic is the tic about to (or currently being) run
  53. maketic is the tick that hasn't had control made for it yet
  54. nettics[] has the maketics for all players
  55.  
  56. a gametic cannot be run until nettics[] > gametic for all players
  57.  
  58. ==============================================================================
  59. */
  60.  
  61. #define    RESENDCOUNT    10
  62. #define    PL_DRONE    0x80                // bit flag in doomdata->player
  63.  
  64. ticcmd_t        localcmds[BACKUPTICS];
  65.  
  66. ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
  67. int             nettics[MAXNETNODES];
  68. boolean            nodeingame[MAXNETNODES];    // set false as nodes leave game
  69. boolean            remoteresend[MAXNETNODES];    // set when local needs tics
  70. int                resendto[MAXNETNODES];            // set when remote needs tics
  71. int                resendcount[MAXNETNODES];
  72.  
  73. int                nodeforplayer[MAXPLAYERS];
  74.  
  75. int             gametime;
  76. int             maketic;
  77. int                lastnettic, skiptics;
  78. int                ticdup;
  79.  
  80. void D_ProcessEvents (void);
  81. void G_BuildTiccmd (ticcmd_t *cmd);
  82. void D_DoAdvanceDemo (void);
  83.  
  84. boolean            reboundpacket;
  85. doomdata_t        reboundstore;
  86.  
  87.  
  88. int    NetbufferSize (void)
  89. {
  90.     return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
  91. }
  92.  
  93. unsigned NetbufferChecksum (void)
  94. {
  95.     unsigned        c;
  96.     int        i,l;
  97.  
  98.     c = 0x1234567;
  99.  
  100.     l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
  101.     for (i=0 ; i<l ; i++)
  102.         c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
  103.  
  104.     return c & NCMD_CHECKSUM;
  105. }
  106.  
  107. int ExpandTics (int low)
  108. {
  109.     int    delta;
  110.  
  111.     delta = low - (maketic&0xff);
  112.  
  113.     if (delta >= -64 && delta <= 64)
  114.         return (maketic&~0xff) + low;
  115.     if (delta > 64)
  116.         return (maketic&~0xff) - 256 + low;
  117.     if (delta < -64)
  118.         return (maketic&~0xff) + 256 + low;
  119.  
  120.     I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
  121.     return 0;
  122. }
  123.  
  124.  
  125. //============================================================================
  126.  
  127.  
  128. /*
  129. ==============
  130. =
  131. = HSendPacket
  132. =
  133. ==============
  134. */
  135.  
  136. void HSendPacket (int node, int flags)
  137. {
  138.     netbuffer->checksum = NetbufferChecksum () | flags;
  139.  
  140.     if (!node)
  141.     {
  142.         reboundstore = *netbuffer;
  143.         reboundpacket = true;
  144.         return;
  145.     }
  146.  
  147.     if (!netgame)
  148.         I_Error ("Tried to transmit to another node");
  149.  
  150.     doomcom->command = CMD_SEND;
  151.     doomcom->remotenode = node;
  152.     doomcom->datalength = NetbufferSize ();
  153.  
  154. if (debugfile)
  155. {
  156.     int        i;
  157.     int        realretrans;
  158.     if (netbuffer->checksum & NCMD_RETRANSMIT)
  159.         realretrans = ExpandTics (netbuffer->retransmitfrom);
  160.     else
  161.         realretrans = -1;
  162.     fprintf (debugfile,"send (%i + %i, R %i) [%i] "
  163.     ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  164.     for (i=0 ; i<doomcom->datalength ; i++)
  165.         fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  166.     fprintf (debugfile,"\n");
  167. }
  168.  
  169.     I_NetCmd ();
  170. }
  171.  
  172. /*
  173. ==============
  174. =
  175. = HGetPacket
  176. =
  177. = Returns false if no packet is waiting
  178. =
  179. ==============
  180. */
  181.  
  182. boolean HGetPacket (void)
  183. {
  184.     if (reboundpacket)
  185.     {
  186.         *netbuffer = reboundstore;
  187.         doomcom->remotenode = 0;
  188.         reboundpacket = false;
  189.         return true;
  190.     }
  191.  
  192.     if (!netgame)
  193.         return false;
  194.  
  195.     doomcom->command = CMD_GET;
  196.     I_NetCmd ();
  197.     if (doomcom->remotenode == -1)
  198.         return false;
  199.  
  200.     if (doomcom->datalength != NetbufferSize ())
  201.     {
  202.         if (debugfile)
  203.             fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
  204.         return false;
  205.     }
  206.  
  207.     if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
  208.     {
  209.         if (debugfile)
  210.             fprintf (debugfile,"bad packet checksum\n");
  211.         return false;
  212.     }
  213.  
  214. if (debugfile)
  215. {
  216.     int        realretrans;
  217.             int    i;
  218.  
  219.     if (netbuffer->checksum & NCMD_SETUP)
  220.         fprintf (debugfile,"setup packet\n");
  221.     else
  222.     {
  223.         if (netbuffer->checksum & NCMD_RETRANSMIT)
  224.             realretrans = ExpandTics (netbuffer->retransmitfrom);
  225.         else
  226.             realretrans = -1;
  227.         fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
  228.         ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  229.         for (i=0 ; i<doomcom->datalength ; i++)
  230.             fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  231.         fprintf (debugfile,"\n");
  232.     }
  233. }
  234.     return true;
  235. }
  236.  
  237.  
  238. /*
  239. ===================
  240. =
  241. = GetPackets
  242. =
  243. ===================
  244. */
  245.  
  246. char    exitmsg[80];
  247.  
  248. void GetPackets (void)
  249. {
  250.     int        netconsole;
  251.     int        netnode;
  252.     int        netdrone;
  253.     int        j;
  254.     ticcmd_t    *src, *dest;
  255.     int        dupedstart, dupedend;
  256.     int        skiptics;
  257.     int        realstart;
  258.  
  259.     while (HGetPacket ())
  260.     {
  261.         if (netbuffer->checksum & NCMD_SETUP)
  262.             continue;        // extra setup packet
  263.  
  264.         netdrone = netbuffer->player & PL_DRONE;
  265.         netconsole = netbuffer->player & ~PL_DRONE;
  266.         netnode = doomcom->remotenode;
  267.         //
  268.         // to save bytes, only the low byte of tic numbers are sent
  269.         // Figure out what the rest of the bytes are
  270.         //
  271.         realstart = ExpandTics (netbuffer->starttic);
  272.         dupedstart = realstart*doomcom->ticdup;
  273.         dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
  274.  
  275.         //
  276.         // check for exiting the game
  277.         //
  278.         if (netbuffer->checksum & NCMD_EXIT)
  279.         {
  280.             if (!nodeingame[netnode])
  281.                 continue;
  282.             nodeingame[netnode] = false;
  283.             if (!netdrone)
  284.             {
  285.                 playeringame[netconsole] = false;
  286.                 strcpy (exitmsg, "PLAYER 1 HAS LEFT THE GAME");
  287.                 exitmsg[7] += netconsole;
  288.                 P_SetMessage(&players[consoleplayer], exitmsg, true);
  289.                 UpdateState |= I_MESSAGES;
  290.                 S_StartSound(NULL, sfx_chat);
  291.             }
  292.             continue;
  293.         }
  294.  
  295.         //
  296.         // drone packets are just notifications
  297.         //
  298.         if (netdrone)
  299.         {
  300.             nettics[netnode] = dupedend;
  301.             continue;
  302.         }
  303.  
  304.         nodeforplayer[netconsole] = netnode;
  305.  
  306.         //
  307.         // check for retransmit request
  308.         //
  309.         if ( resendcount[netnode] <= 0
  310.         && (netbuffer->checksum & NCMD_RETRANSMIT) )
  311.         {
  312.             resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
  313. if (debugfile)
  314. fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
  315.             resendcount[netnode] = RESENDCOUNT;
  316.         }
  317.         else
  318.             resendcount[netnode]--;
  319.  
  320.         //
  321.         // check for out of order / duplicated packet
  322.         //
  323.         if (dupedend == nettics[netnode])
  324.             continue;
  325.  
  326.         if (dupedend < nettics[netnode])
  327.         {
  328. if (debugfile)
  329. fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
  330.             continue;
  331.         }
  332.  
  333.         //
  334.         // check for a missed packet
  335.         //
  336.         if (dupedstart > nettics[netnode])
  337.         {
  338.         // stop processing until the other system resends the missed tics
  339. if (debugfile)
  340. fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
  341.             remoteresend[netnode] = true;
  342.             continue;
  343.         }
  344.  
  345. //
  346. // update command store from the packet
  347. //
  348.         remoteresend[netnode] = false;
  349.  
  350.         skiptics = nettics[netnode]/doomcom->ticdup - realstart;
  351.         src = &netbuffer->cmds[skiptics];
  352.  
  353.         while (nettics[netnode] < dupedend)
  354.         {
  355.             for (j=0 ; j<doomcom->ticdup ; j++)
  356.             {
  357.                 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
  358.                 nettics[netnode]++;
  359.                 *dest = *src;
  360.                 src->chatchar = 0;
  361.                 if (src->buttons & BT_SPECIAL)
  362.                     src->buttons = 0;
  363.             }
  364.             src++;
  365.         }
  366.     }
  367. }
  368.  
  369. /*
  370. =============
  371. =
  372. = NetUpdate
  373. =
  374. = Builds ticcmds for console player
  375. = sends out a packet
  376. =============
  377. */
  378.  
  379. void NetUpdate (void)
  380. {
  381.     int             nowtime;
  382.     int             newtics;
  383.     int                i,j;
  384.     int                gameticdiv;
  385.     int                realstart;
  386.  
  387.     if (singletics)
  388.         return;         // singletic update is syncronous
  389.  
  390. //
  391. // check time
  392. //
  393.     nowtime = I_GetTime ()/doomcom->ticdup;
  394.     newtics = nowtime - gametime;
  395.     gametime = nowtime;
  396.     if (newtics <= 0)                       // nothing new to update
  397.         goto listen;
  398.  
  399.     if (skiptics <= newtics)
  400.     {
  401.         newtics -= skiptics;
  402.         skiptics = 0;
  403.     }
  404.     else
  405.     {
  406.         skiptics -= newtics;
  407.         newtics = 0;
  408.     }
  409.  
  410.  
  411.     netbuffer->player = consoleplayer;
  412.     if (doomcom->drone)
  413.         netbuffer->player |= PL_DRONE;
  414.  
  415. //
  416. // drone packets
  417. //
  418.     if (doomcom->drone)
  419.     {
  420.         I_StartTic ();
  421.         D_ProcessEvents ();
  422.         goto sendit;
  423.     }
  424.  
  425. //
  426. // build new ticcmds for console player
  427. //
  428.     gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
  429.     for (i=0 ; i<newtics ; i++)
  430.     {
  431.         I_StartTic ();
  432.         D_ProcessEvents ();
  433.         if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
  434.         {
  435.             newtics = i;
  436.             break;          // can't hold any more
  437.         }
  438. //printf ("mk:%i ",maketic);
  439.         G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
  440.         maketic++;
  441.     }
  442.  
  443. //
  444. // send the packet to the other nodes
  445. //
  446. sendit:
  447.     for (i=0 ; i<doomcom->numnodes ; i++)
  448.         if (nodeingame[i])
  449.         {
  450.             if (doomcom->drone)
  451.             {
  452.                 netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
  453.                 netbuffer->numtics = 0;
  454.             }
  455.             else
  456.             {
  457.                 netbuffer->starttic = realstart = resendto[i];
  458.                 netbuffer->numtics = maketic - realstart;
  459.                 resendto[i] = maketic - doomcom->extratics;
  460.             }
  461.  
  462.             if (netbuffer->numtics > BACKUPTICS)
  463.                 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
  464.  
  465.             for (j=0 ; j< netbuffer->numtics ; j++)
  466.                 netbuffer->cmds[j] =
  467.                     localcmds[(realstart+j)%BACKUPTICS];
  468.  
  469.             if (remoteresend[i])
  470.             {
  471.                 netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
  472.                 HSendPacket (i, NCMD_RETRANSMIT);
  473.             }
  474.             else
  475.             {
  476.                 netbuffer->retransmitfrom = 0;
  477.                 HSendPacket (i, 0);
  478.             }
  479.         }
  480.  
  481. //
  482. // listen for other packets
  483. //
  484. listen:
  485.  
  486.     GetPackets ();
  487. }
  488.  
  489.  
  490. /*
  491. =====================
  492. =
  493. = CheckAbort
  494. =
  495. =====================
  496. */
  497.  
  498. void CheckAbort (void)
  499. {
  500.     event_t *ev;
  501.  
  502.     I_WaitVBL(2);
  503.  
  504.     I_StartTic ();
  505.     for ( ; eventtail != eventhead
  506.     ; eventtail = (++eventtail)&(MAXEVENTS-1) )
  507.     {
  508.         ev = &events[eventtail];
  509.         if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
  510.             I_Error ("Network game synchronization aborted.");
  511.     }
  512. }
  513.  
  514. /*
  515. =====================
  516. =
  517. = D_ArbitrateNetStart
  518. =
  519. =====================
  520. */
  521.  
  522. void D_ArbitrateNetStart (void)
  523. {
  524.     int        i;
  525.     boolean    gotinfo[MAXNETNODES];
  526.  
  527.     autostart = true;
  528.     memset (gotinfo,0,sizeof(gotinfo));
  529.  
  530.     if (doomcom->consoleplayer)
  531.     {    // listen for setup info from key player
  532.         //printf ("listening for network start info...\n");
  533.         while (1)
  534.         {
  535.             CheckAbort ();
  536.             if (!HGetPacket ())
  537.                 continue;
  538.             if (netbuffer->checksum & NCMD_SETUP)
  539.             {
  540.                 if (netbuffer->player != VERSION)
  541.                     I_Error ("Different HERETIC versions cannot play a net game!");
  542.                 startskill = netbuffer->retransmitfrom & 15;
  543.                 deathmatch = (netbuffer->retransmitfrom & 0x80) > 0;
  544.                 startmap = netbuffer->starttic & 15;
  545.                 startepisode = netbuffer->starttic >> 4;
  546.                 return;
  547.             }
  548.         }
  549.     }
  550.     else
  551.     {    // key player, send the setup info
  552. //        printf ("sending network start info...\n");
  553.         do
  554.         {
  555.             CheckAbort ();
  556.             for (i=0 ; i<doomcom->numnodes ; i++)
  557.             {
  558.                 netbuffer->retransmitfrom = startskill;
  559.                 if (deathmatch)
  560.                     netbuffer->retransmitfrom |= 0x80;
  561.                 netbuffer->starttic = startepisode * 16 + startmap;
  562.                 netbuffer->player = VERSION;
  563.                 netbuffer->numtics = 0;
  564.                 HSendPacket (i, NCMD_SETUP);
  565.             }
  566.  
  567.             while (HGetPacket ())
  568.             {
  569. //printf ("got packet\n");
  570.                 gotinfo[netbuffer->player&0x7f] = true;
  571.             }
  572.  
  573.             for (i=1 ; i<doomcom->numnodes ; i++)
  574.                 if (!gotinfo[i])
  575.                     break;
  576.         } while (i < doomcom->numnodes);
  577.     }
  578. }
  579.  
  580. /*
  581. ===================
  582. =
  583. = D_CheckNetGame
  584. =
  585. = Works out player numbers among the net participants
  586. ===================
  587. */
  588.  
  589. extern    int            viewangleoffset;
  590.  
  591. void D_CheckNetGame (void)
  592. {
  593.     int             i;
  594.  
  595.     for (i=0 ; i<MAXNETNODES ; i++)
  596.     {
  597.         nodeingame[i] = false;
  598.            nettics[i] = 0;
  599.         remoteresend[i] = false;    // set when local needs tics
  600.         resendto[i] = 0;            // which tic to start sending
  601.     }
  602.  
  603. // I_InitNetwork sets doomcom and netgame
  604.     I_InitNetwork ();
  605.     if (doomcom->id != DOOMCOM_ID)
  606.         I_Error ("Doomcom buffer invalid!");
  607.     netbuffer = &doomcom->data;
  608.     consoleplayer = displayplayer = doomcom->consoleplayer;
  609.     if (netgame)
  610.         D_ArbitrateNetStart ();
  611. //printf ("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
  612.  
  613. // read values out of doomcom
  614.     ticdup = doomcom->ticdup;
  615.  
  616.     for (i=0 ; i<doomcom->numplayers ; i++)
  617.         playeringame[i] = true;
  618.     for (i=0 ; i<doomcom->numnodes ; i++)
  619.         nodeingame[i] = true;
  620.  
  621. //printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
  622.  
  623. }
  624.  
  625. /*
  626. ==================
  627. =
  628. = D_QuitNetGame
  629. =
  630. = Called before quitting to leave a net game without hanging the
  631. = other players
  632. =
  633. ==================
  634. */
  635.  
  636. void D_QuitNetGame (void)
  637. {
  638.     int             i, j;
  639.  
  640.     if (debugfile)
  641.         fclose (debugfile);
  642.  
  643.     if (!netgame || !usergame || consoleplayer == -1)
  644.         return;
  645.  
  646. // send a bunch of packets for security
  647.     netbuffer->player = consoleplayer;
  648.     if (doomcom->drone)
  649.         netbuffer->player |= PL_DRONE;
  650.     netbuffer->numtics = 0;
  651.     for (i=0 ; i<4 ; i++)
  652.     {
  653.         for (j=1 ; j<doomcom->numnodes ; j++)
  654.             if (nodeingame[j])
  655.                 HSendPacket (j, NCMD_EXIT);
  656.         I_WaitVBL (1);
  657.     }
  658. }
  659.  
  660.  
  661.  
  662. /*
  663. ===============
  664. =
  665. = TryRunTics
  666. =
  667. ===============
  668. */
  669.  
  670. int    frametics[4], frameon;
  671. int    frameskip[4];
  672. int        oldnettics;
  673. extern    boolean    advancedemo;
  674.  
  675. void TryRunTics (void)
  676. {
  677.     int             i;
  678.     int             lowtic, nextlowest;
  679.     int             entertic;
  680.     int    static        oldentertics;
  681.     int                realtics, availabletics;
  682.     int                counts;
  683.     int                numplaying;
  684.  
  685. //
  686. // get real tics
  687. //
  688.     entertic = I_GetTime ();
  689.     realtics = entertic - oldentertics;
  690.     oldentertics = entertic;
  691.  
  692. //
  693. // get available tics
  694. //
  695.     NetUpdate ();
  696.  
  697.     lowtic = nextlowest = MAXINT;
  698.     numplaying = 0;
  699.     for (i=0 ; i<doomcom->numnodes ; i++)
  700.         if (nodeingame[i])
  701.         {
  702.             numplaying++;
  703.             if (nettics[i] < lowtic)
  704.             {
  705.                 nextlowest = lowtic;
  706.                 lowtic = nettics[i];
  707.             }
  708.             else if (nettics[i] < nextlowest)
  709.                 nextlowest = nettics[i];
  710.         }
  711.     availabletics = lowtic - gametic;
  712.  
  713.  
  714. //
  715. // decide how many tics to run
  716. //
  717.     if (realtics < availabletics-1)
  718.         counts = realtics+1;
  719.     else if (realtics < availabletics)
  720.         counts = realtics;
  721.     else
  722.         counts = availabletics;
  723.     if (counts < 1)
  724.         counts = 1;
  725.  
  726.     frameon++;
  727.  
  728. if (debugfile)
  729.     fprintf (debugfile,"=======real: %i  avail: %i  game: %i\n",realtics, availabletics,counts);
  730.  
  731. //=============================================================================
  732. //
  733. //    ideally nettics[0] should be 1 - 3 tics above lowtic
  734. //    if we are consistantly slower, speed up time
  735. //    drones should never hold up the other players
  736. //
  737.     for (i=0 ; i<MAXPLAYERS ; i++)
  738.         if (playeringame[i])
  739.             break;
  740.     if (consoleplayer == i)
  741.     {    // the key player does not adapt
  742.     }
  743.     else
  744.     {
  745.         if (nettics[0] <= nettics[nodeforplayer[i]])
  746.         {
  747.             gametime--;
  748. //            printf ("-");
  749.         }
  750.         frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
  751.         oldnettics = nettics[0];
  752.         if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
  753.         {
  754.             skiptics = 1;
  755. //            printf ("+");
  756.         }
  757.     }
  758. //=============================================================================
  759.  
  760. //
  761. // wait for new tics if needed
  762. //
  763.     while (lowtic < gametic + counts)
  764.     {
  765.  
  766.         NetUpdate ();
  767.         lowtic = MAXINT;
  768.  
  769.         for (i=0 ; i<doomcom->numnodes ; i++)
  770.             if (nodeingame[i] && nettics[i] < lowtic)
  771.                 lowtic = nettics[i];
  772.  
  773.         if (lowtic < gametic)
  774.             I_Error ("TryRunTics: lowtic < gametic");
  775.  
  776.         // don't stay in here forever -- give the menu a chance to work
  777.         if (I_GetTime () - entertic >= 20)
  778.         {
  779.             MN_Ticker ();
  780.             return;
  781.         }
  782.     }
  783.  
  784.  
  785. //
  786. // run the tics
  787. //
  788.     while (counts--)
  789.     {
  790.         if (advancedemo)
  791.             D_DoAdvanceDemo ();
  792.         MN_Ticker ();
  793.         G_Ticker ();
  794.         NetUpdate ();                    // check for new console commands
  795.         gametic++;
  796.     }
  797. }
  798.